import * as echarts from 'echarts';
import { EChartsType } from 'echarts';

export const debounce = (fn: Function, delay: number): any => {
	let timer: any = null;
	return function (this: any, ...args: any) {
		if (timer) clearTimeout(timer);

		timer = setTimeout(() => {
			fn.apply(this, args);
		}, delay);
	};
};

export default function useEcharts(props: any, domWrapper: any) {
	const chart = shallowRef<EChartsType | null>(null);

	const updateChart = () => {
		if (unref(chart) && props.options) {
			nextTick(() => unref(chart)!.setOption(props.options, true));
		}
	};

	const handleChartResize = debounce(() => {
		unref(chart)?.resize();
	}, 200);

	onMounted(() => {
		window.addEventListener('resize', handleChartResize);
		initMutationObserver();
	});

	onBeforeMount(() => {
		window.removeEventListener('resize', handleChartResize);
		removeMutationObserver();
	});

	watch(() => props.options, updateChart);

	/**
	 * 同步语句创建的侦听器，会自动绑定到宿主组件实例上，并且会在宿主组件卸载时自动停止。
	 * 因此，在大多数情况下，你无需关心怎么停止一个侦听器。
	 *
	 * 一个关键点是，侦听器必须用同步语句创建：如果用异步回调创建一个侦听器，
	 * 那么它不会绑定到当前组件上，你必须手动停止它
	 *
	 * watchPostEffect => 在dom更新完之后调用
	 */
	watchPostEffect(() => {
		// 销毁实例, 避免错误警告：[ECharts] There is a chart instance already initialized on the dom.
		unref(chart)?.dispose();

		chart.value = echarts.init(domWrapper.value as HTMLElement);
	});

	// 容器 style (这里指宽度) 发生改变的时候，触发 handleChartResize 函数
	const observer = ref<MutationObserver | null>(null);
	const initMutationObserver = () => {
		observer.value = new MutationObserver(handleChartResize);
		observer.value.observe(domWrapper.value, {
			attributeFilter: ['style'],
			attributeOldValue: true,
		});
	};

	const removeMutationObserver = () => {
		if (!observer.value) return;
		observer.value.disconnect();
	};

	return {
		chart,
	};
}
